// part1:C09:ex9.52.cpp
// stack and parentheses.
#include <cstddef>
#include <ios>
#include <iostream>
#include <type_traits>
#include <vector>
#include <deque>
#include <stack>
#include <stdexcept>
using namespace std;

enum obj_type { LP, RP, ADD, SUB, VAL };
struct obj {
  obj(obj_type type, double val = 0) { t = type; v = val; } 
  obj_type t;
  double v;
};

inline void skipws(string& exp, size_t& p) {
  p = exp.find_first_not_of(" ", p);
}

inline void new_val(stack<obj>& so, double v) {
  if (so.empty() || so.top().t == LP) { // empty stack or left parentheses
    so.push(obj(VAL, v));
    // cout << "push" << v << endl;
  } else if (so.top().t == ADD || so.top().t == SUB){
    obj_type type = so.top().t;
    so.pop();
    /*if (type == ADD) {
        cout << "pop +" << endl;
      } else {
        cout << "pop -" << endl;
      }
     */
    // cout << "pop " << so.top().v << endl;

    // ADD and SUB
    if (type == ADD) {
      v += so.top().v; 
    } else {
      v = so.top().v - v;
    }
    so.pop();
    so.push(obj(VAL, v));
    // cout << "push" << v << endl;
  } else {
    throw invalid_argument("missing operator!");
  } 
}

int main(void) {
  stack<obj> so;
  string exp;
  size_t p = 0, curr;
  double v;

  cout << "Enter expression:\n";
  getline(cin, exp);
  while (p < exp.size()) {
    skipws(exp, p);
    if (exp[p] == '(') {
      so.push(obj(LP));
      p++;
      // cout << "push LP" << endl;
    } else if (exp[p] == '+' || exp[p] == '-') {
      if (so.empty() || so.top().t != VAL) {
        // empty stack or before not operator
        throw invalid_argument("missing operator!");
      }

      if (exp[p] == '+') {  // push operator
        so.push(obj(ADD));
      } else {
        so.push(obj(SUB));
      }
      p++;
      // cout << "push " << exp[p - 1] << endl;
    } else if (exp[p] == ')') { // right parentheses
      p++;
      if (so.empty()) {
        throw invalid_argument("not pattern right parentheses!");
      }

      if (so.top().t == LP) {
        // no contents between pair of parentheses
        throw invalid_argument("empty parentheses!");
      }

      if (so.top().t == VAL) {  // right results: contents in parentheses 
        v = so.top().v;
        so.pop();
        // cout << "pop " << v << endl;
        if (so.empty() || so.top().t != LP) {
          throw invalid_argument("not pattern right parentheses!");
        }
        so.pop();
        // cout << "pop LP" << endl;
        new_val(so, v);
      } else { // should be values
        throw invalid_argument("missing values!");
      }
     } else {
      v = stod(exp.substr(p), &curr);
      p += curr;
      new_val(so, v);
    }
  }

  if (so.size() != 1 || so.top().t != VAL) {
    throw invalid_argument("wrong expression!");
  }
  cout << so.top().v << endl;
  return 0;
}
